package com.morningstar.qs.basic.db.util;

import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.RootClass;

import com.morningstar.qs.basic.db.exception.SessionFactoryInitializationException;


public final class HibernateMultipleDatabaseUtil {
	private static Logger gLogger = Logger.getLogger(HibernateMultipleDatabaseUtil.class);
	
	private HibernateMultipleDatabaseUtil() {
	}

	private static Map<String, SessionFactory> sessionFactories;
	private static HibernateMultipleDatabaseUtil instance;
	private String[] hibernateConfigFiles;
	private boolean isInitialization = false;

	public static HibernateMultipleDatabaseUtil getInstance() {
		if (instance == null)
			instance = new HibernateMultipleDatabaseUtil();
		return instance;
	}

	public String[] getHibernateConfigFiles() {
		return hibernateConfigFiles;
	}

	public void setHibernateConfigFiles(String[] hibernateConfigFiles) {
		this.hibernateConfigFiles = hibernateConfigFiles;
	}

	private synchronized void initSessionFactory() throws SessionFactoryInitializationException {
		gLogger.info("Start to initialize the hibernate configuration files...");
		if (!isInitialization) {
			sessionFactories = new HashMap<String, SessionFactory>();
			String[] files;
			if (hibernateConfigFiles == null) {
				files = new String[1];
//				files[0] = "Hibernate.cfg.xml";
//				files[1] = "RealTimeBaseInfo.cfg.xml";
//				files[2] = "UserProfiles.cfg.xml";
				gLogger.warn("Hibernate configuration files is not found.....");
//				files[0] = HibernateConfig.getInstance().getHcxmlUserAuthentication();
//				files[1] = HibernateConfig.getInstance().getHcxmlRealTimeBaseInfo();
//				files[1] = HibernateConfig.getInstance().getHcxmlUserProfiles();
				
			} else {
				files = new String[hibernateConfigFiles.length];
				for (int i = 0; i < hibernateConfigFiles.length; i++) {
					files[i] = hibernateConfigFiles[i];
					gLogger.warn("Hibernate configuration files. NO: "+i+" file name:"+files[i]);
				}
			}
			
			Configuration cfg = null;

			for (String pathname : files) {
				cfg = new Configuration();

//				URL ulr = Thread.currentThread().getContextClassLoader().getResource(pathname);
				URL ulr = this.getClass().getClassLoader().getResource(pathname);
//				 System.out.println("ulr:"+(ulr==null));
				gLogger.warn("Init hibernate configuration file..."+pathname);
				cfg = cfg.configure(ulr);
				SessionFactory sf = cfg.buildSessionFactory();
				catchSessionFactory(sf, cfg, pathname);
			}
		}
		isInitialization = true;
	}

	@SuppressWarnings("unchecked")
	private void catchSessionFactory(SessionFactory sf, Configuration cfg, String configurationFile) {
		Iterator classes = cfg.getClassMappings();
		int i = 0;
		while (classes.hasNext()) {
			Object o = classes.next();
			RootClass rc = (RootClass) o;
			//gLogger.info("Register O-R mapping file:\t" + rc.getClassName());
			sessionFactories.put(rc.getClassName(), sf);
			i++;
		}

		gLogger.info("Register " + i + " O-R mapping files into session factory corresponded to file " + configurationFile);

	}

	/**
	 * Return a new Session object that must be closed when the work has been
	 * 
	 * @param clasz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Session getSession(Class clasz) {
		if (sessionFactories == null) {
			try {
				HibernateMultipleDatabaseUtil.getInstance().initSessionFactory();
			} catch (SessionFactoryInitializationException e) {
				e.printStackTrace();
			}
		}
		if (clasz == null)
			throw new NullPointerException("clasz is not allowed empty.");
		if (sessionFactories == null)
			throw new NullPointerException("Session factoryes is empty.");
		if (clasz.getName() == null)
			new IllegalArgumentException("clasz.getName() is empty.clasz.toString()\t" + clasz.toString());
		SessionFactory factory = sessionFactories.get(clasz.getName());
		if (factory == null)
			throw new NullPointerException("Session factory corresponding bean " + clasz.getName() + " is empty.");
		return factory.openSession();
	}

}
